import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import
{
    AmbientLight, BoxGeometry, Mesh, MeshLambertMaterial, OrthographicCamera, TextureLoader, MeshBasicMaterial,
    PointLight, Scene, SphereGeometry, WebGLRenderer, ArrowHelper, Vector3, Camera, Raycaster, Vector2, Object3D, RepeatWrapping, PlaneGeometry, PerspectiveCamera
} from 'three';
import tri_pattern from '../../../assets/img/tri_pattern.jpg';
import hot from '../../../assets/img/hot.png';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';//直接引用包里面的
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import { Color } from 'three';

@observer
export default class FirstThreeDScene extends Component<{}, {}>
{
    @observable myDemo = document.getElementById("myScene") as HTMLDivElement;
    @observable scene = new Scene(); //场景:就是图形渲染的画布
    @observable camera = new OrthographicCamera( //相机:就是你观察的视角,相机的选择决定了相机的操作
        -150 * (this.myDemo.offsetWidth / this.myDemo.offsetHeight), //视野角度
        150 * (this.myDemo.offsetWidth / this.myDemo.offsetHeight), //长宽比
        150,
        -150,
        1, //近截面
        1000 //远截面 超出远截面或小于近截面就不渲染
    );
    @observable renderer = new WebGLRenderer(); //渲染器:建立好了模型需要用渲染器渲染
    @observable geometryCube = new BoxGeometry(100, 200, 10); //几何图形:建一个什么样的形状,这是一个正方体
    @observable geometrySphere = new SphereGeometry(40, 40, 40); //这是一个球体
    @observable material = new MeshLambertMaterial({ //材质的选择决定是否受光照影响
        color: 0x13c2c2
    }); //材质对象Material:渲染出个什么样的物体
    @observable cube = new Mesh(this.geometryCube, this.material); //这才是模型对象,网格模型对象,用什么形状,什么材质渲染
    @observable sphere = new Mesh(this.geometrySphere, this.material);
    @observable pointLight = new PointLight(0xffffff);//点光源
    @observable ambient = new AmbientLight(0x444444);//环境光
    @observable control = new OrbitControls(this.camera, this.renderer.domElement);//控制相机到处看

    //三根辅助箭头
    @observable arrowHelperY = new ArrowHelper(new Vector3(0, 1, 0), new Vector3(0, 0, 0), 250, 0x00ff00);
    @observable arrowHelperX = new ArrowHelper(new Vector3(1, 0, 0), new Vector3(0, 0, 0), 250, 0xff0000);
    @observable arrowHelperZ = new ArrowHelper(new Vector3(0, 0, 1), new Vector3(0, 0, 0), 250, 0x0000ff);
    @observable poiOb: Object3D[] = []; //所有模型的位置
    @observable poiObBorder: Object3D[] = [];
    @action setScene = (scene: Scene, camera: Camera, renderer: WebGLRenderer) =>
    {
        //设置箭头坐标
        scene.add(this.arrowHelperY);
        scene.add(this.arrowHelperX);
        scene.add(this.arrowHelperZ);


        this.pointLight.position.set(-400, 200, -300); //设置点光源位置

        scene.add(this.pointLight); //添加点光源
        scene.add(this.ambient); //添加环境光

        renderer.setSize(this.myDemo.offsetWidth, this.myDemo.offsetHeight);
        this.myDemo.appendChild(this.renderer.domElement);

        camera.position.set(-200, 300, -200);
        camera.lookAt(scene.position);
    };

    @action
    renderCube = () =>
    {
        let secondCube = new Mesh(this.geometryCube, this.material);
        secondCube.position.set(0, 0, 120);
        let plane = new Mesh(new PlaneGeometry(10, 10), new MeshBasicMaterial({ map: new TextureLoader().load(hot, () => { this.myRender(); }) }));
        plane.position.set(0, 0, 150);
        // this.cube.position.set(0, 120, 120);
        this.scene.add(this.cube);
        this.scene.add(secondCube);
        this.scene.add(plane);
        this.poiOb.push(this.cube);
        this.poiOb.push(secondCube);
        this.poiOb.push(plane);

        this.sphere.position.set(200, 120, 0);
        this.scene.add(this.sphere);
        this.poiOb.push(this.sphere);

        this.setScene(this.scene, this.camera, this.renderer);

        this.myRender();
    };
    @action
    myRender = () =>
    {
        // this.renderer.render(this.scene, this.camera);
        this.composer.render();
    };
    raycast = (e: MouseEvent) =>
    {
        let canvas = e.target as HTMLCanvasElement;
        e.preventDefault();

        let raycaster = new Raycaster();
        let mouse = new Vector2();
        //将鼠标点击位置的屏幕坐标转成threejs中的标准坐标
        mouse.x = ((e.clientX - 256) / canvas.clientWidth) * 2 - 1;
        mouse.y = -(e.clientY / canvas.clientHeight) * 2 + 1;

        raycaster.setFromCamera(mouse, this.camera);
        let intersect = raycaster.intersectObjects(this.poiOb);
        if (intersect.length > 0)
        {
            this.poiObBorder = [];
            this.poiObBorder.push(intersect[0].object);
            this.outlinepass.selectedObjects = this.poiObBorder;
            this.myRender();
            console.log(intersect);
        }
        else
        {
            this.outlinepass.selectedObjects = [];
            this.myRender();
        }

    };
    @observable composer = new EffectComposer(this.renderer);
    @observable outlinepass = new OutlinePass(new Vector2(this.myDemo.offsetWidth, this.myDemo.offsetHeight), this.scene, this.camera);

    setUpComposer() //初始化效果编辑器
    {
        this.composer.setSize(this.myDemo.offsetWidth, this.myDemo.offsetHeight);

        this.outlinepass.visibleEdgeColor = new Color('#ffffff');
        this.outlinepass.hiddenEdgeColor = new Color('#ff0000');

        let renderpass = new RenderPass(this.scene, this.camera);
        this.composer.addPass(renderpass);
        this.composer.addPass(this.outlinepass);

        const textureLoader = new TextureLoader();
        textureLoader.load(tri_pattern, (texture) =>
        {
            this.outlinepass.patternTexture = texture;
            texture.wrapS = RepeatWrapping;
            texture.wrapT = RepeatWrapping;
        });

        let effectFXAA = new ShaderPass(FXAAShader);
        effectFXAA.uniforms['resolution'].value.set(   //设置分辨率
            1 / this.myDemo.offsetWidth, 1 / this.myDemo.offsetHeight
        );
        this.composer.addPass(effectFXAA);

        //重新计算分辨率
        window.addEventListener('resize', () =>
        {
            console.log("im resize");
            const width = this.myDemo.offsetWidth;
            const height = this.myDemo.offsetHeight;

            // this.camera.aspect = width / height;
            this.camera.updateProjectionMatrix();

            this.renderer.setSize(width, height);
            this.composer.setSize(width, height);
            effectFXAA.uniforms['resolution'].value.set(
                1 / this.myDemo.offsetWidth, 1 / this.myDemo.offsetHeight
            );
        });

        this.renderer.domElement.addEventListener('mousemove', (e) => { this.raycast(e); });
    }

    componentDidMount() //等待我DIV出来
    {
        this.setUpComposer();
        this.renderer.setClearColor(0x00000, 1);

        this.renderCube();

        this.control.enablePan = false; //禁止拖拽 改变原点位置
        this.control.enableDamping = true;//轨道控制 是否有惯性 阻尼。。。
        this.control.dampingFactor = .2; //阻尼数值
        this.control.addEventListener('change', this.myRender);

        let transControl = new TransformControls(this.camera, this.renderer.domElement);
        transControl.setMode("scale");
        transControl.addEventListener("change", this.myRender);
        transControl.addEventListener('dragging-changed', (e) =>
        {
            this.control.enabled = !e.value;
        });

        transControl.attach(this.cube);
        this.scene.add(transControl);
    }
    render()
    {
        return (
            <div id="myScene" style={{ width: "100%", height: "100%" }} >

            </ div>
        );
    }
}
